package typedef

import (
	"fmt"
	"time"
	"sync"
)

func ClearScreen() {
	fmt.Print("\033c")
}

type Lckint struct {
	value int
	lock sync.RWMutex
}

func (this *Lckint) AddOne() {
	this.lock.Lock()
	this.value += 1
	this.lock.Unlock()
}

func (this *Lckint) Value() int {
	var tmp int
	this.lock.RLock()
	tmp = this.value
	this.lock.RUnlock()
	return tmp
}

func (this *Lckint) SetZero() {
	this.lock.Lock()
	this.value = 0
	this.lock.Unlock()
}

// Struct for status
type Status struct {
	quitOutput bool
	chanWaitExit chan int

	StartTime time.Time
	// status var
	WriteSF Lckint
	WriteSuccess Lckint
	WriteFailed Lckint
	WriteSkip Lckint
	ReadSF Lckint
	ReadSuccess Lckint
	ReadFailed Lckint
	ReadSkip Lckint
	DeleteSF Lckint
	DeleteSuccess Lckint
	DeleteFailed Lckint
	DeleteSkip Lckint
}

func (this *Status) AddOne(action string, result string) {
	if action == "WRITE" {
		if result == "SUCCESS" {
			this.WriteSuccess.AddOne()
			this.WriteSF.AddOne()
		} else if result == "FAILED" {
			this.WriteFailed.AddOne()
			this.WriteSF.AddOne()
		} else if result == "SKIP" {
			this.WriteSkip.AddOne()
		}
	} else if action == "READ" {
		if result == "SUCCESS" {
			this.ReadSuccess.AddOne()
			this.ReadSF.AddOne()
		} else if result == "FAILED" {
			this.ReadFailed.AddOne()
			this.ReadSF.AddOne()
		} else if result == "SKIP" {
			this.ReadSkip.AddOne()
		}
	} else if action == "DELETE" {
		if result == "SUCCESS" {
			this.DeleteSuccess.AddOne()
			this.DeleteSF.AddOne()
		} else if result == "FAILED" {
			this.DeleteFailed.AddOne()
			this.DeleteSF.AddOne()
		} else if result == "SKIP" {
			this.DeleteSkip.AddOne()
		}
	}
}

func (this *Status) ExitStatus() {
	this.quitOutput = true
	<-this.chanWaitExit
}

func (this *Status) ShowStatus(timeout int) {
	this.quitOutput = false
	this.chanWaitExit = make(chan int)
	go func() {
		var (
			curTime time.Time
			lastWriteSF int
			lastReadSF int
			lastDeleteSF int
		)
		defer func() {
			this.quitOutput = false
			this.chanWaitExit <- 1
		} ()

		lastWriteSF = this.WriteSF.Value()
		lastReadSF = this.ReadSF.Value()
		lastDeleteSF = this.DeleteSF.Value()
		for this.quitOutput == false {
			if timeout <= 0 {
				timeout = 2
			}
			ClearScreen()
			// Output base info.
			curTime = time.Now()
			fmt.Println("**type \"q\" or \"quit\", and press ENTER to quit Status View.**")
			fmt.Println(curTime)
			fmt.Println("")
			fmt.Printf("Action\tSuccess\tFailed\tSkip\tfile/s\n")
			fmt.Printf("Write\t%d\t%d\t%d\t%f\n",
				this.WriteSuccess.Value(),
				this.WriteFailed.Value(),
				this.WriteSkip.Value(),
				float32(this.WriteSF.Value() - lastWriteSF) / float32(timeout) )
			fmt.Printf("Read\t%d\t%d\t%d\t%f\n",
				this.ReadSuccess.Value(),
				this.ReadFailed.Value(),
				this.ReadSkip.Value(),
				float32(this.ReadSF.Value() - lastReadSF) / float32(timeout) )
			fmt.Printf("Delete\t%d\t%d\t%d\t%f\n",
				this.DeleteSuccess.Value(),
				this.DeleteFailed.Value(),
				this.DeleteSkip.Value(),
				float32(this.DeleteSF.Value() - lastDeleteSF) / float32(timeout) )
			lastWriteSF = this.WriteSF.Value()
			lastReadSF = this.ReadSF.Value()
			lastDeleteSF = this.DeleteSF.Value()

			// Output average speed.

			// wait loop timeout
			time.Sleep(time.Second * time.Duration(timeout))
		}
	} ()
}

func (this *Status) Empty() {
	this.WriteSF.SetZero()
	this.WriteSuccess.SetZero()
	this.WriteFailed.SetZero()
	this.WriteSkip.SetZero()
	this.ReadSF.SetZero()
	this.ReadSuccess.SetZero()
	this.ReadFailed.SetZero()
	this.ReadSkip.SetZero()
	this.DeleteSF.SetZero()
	this.DeleteSuccess.SetZero()
	this.DeleteFailed.SetZero()
	this.DeleteSkip.SetZero()
}

